Мои ошибки

R
Автор

Е. Тымченко

Дата публикации

2 января 2026 г.

В 2025 году я замечал много недочётов в своём программировании. В целом, в R я предпочитаю функциональный стиль. Это должно быть заметно по большинству постов. При этом, часто я выбирал неоптимальные алгоритмы или использовал устаревшие функции из base R в tidy-пайплайнах. Всё это сказывалось на читаемости и производительности.

Всё это привело меня к работе над ошибками. Я составил табличку на основе кусочков кода, которые вызывали у меня наибольшее отторжение. Это помогло запомнить основные ошибки и исправить их. Этот список — про осознанный переход от «работает и ладно» к чистому, быстрому и поддерживаемому коду.

Тема Раньше я делал так Теперь я делаю так Пример/Коммент
Base R -> Tidyverse na.omit() из base R drop_na из dplyr Быстрее и можно указыать столбцы.
Base R -> Tidyverse read.csv read_csv из readr или data_table:fread C++ имплементация намного-намного быстрее, особенно для больших файлов.
Base R -> Tidyverse write.csv arrow::write_parquet Намного быстрее, не теряются типы, файлы меньше весят.
Операции с данными Всегда делал group_by Комбинирую с nest, unnest. group_by лучше для векторизованных операций. nest - для параллельных вычислений на переменных-списках.
Операции с данными В mutate много писал повторяющихся операций с разными векторами. Использую across Лаконичный код. Удобно масштабировать.
Операции с данными Разбивал пайплайн на микропайплайны, писал функции на 1 раз. map, map2 Большие, читаемые пайплайны.
Даты as.Date() из base R lubridate. Например:

Быстрее, лаконичнее, проще читается

- ymd('2025/01/25')

- year(date)

  • ymd_hm("2025-01-25 00:51")
Дебаггинг Разбирал пайплайн на части Использую debugonce() Очень удобно, ускоряет отладку.
Стиль Писал повторяющиеся операции много раз Общие функции для повторов Код компактнее, ноутбуки читаемее.
Списки Доставал элементы через $ Для дропа NULL использую compact() Удобно, лаконично.
Пространственные данные Использовал osmdata osmextract быстрее и стабильнее Работает лучше на больших данных.
Запись данных Повторял одну функцию для записи файлов walk, iwalk

Чистый функциональный подход, удобно сохранять слои layers <- list(grass = grass, flowerbed = flowerbed, fountain = fountain, garden = garden)

iwalk(layers, ~ st_write(.x, paste0(“osm_”, .y, “.gpkg”), delete_dsn = TRUE))

Обработка данных Использовал rbind | bind_rows из dplyr
bind_rows из dplyr
Не нужно следить за порядком столбцов, быстрее.
Обработка данных Много join подряд | reduce, pivot_longer / join / pivot_wider | |
reduce, pivot_longer / join / pivot_wider
Более читаемый, универсальный стиль.
dfs <- list(df1, df2, df3, df4)
big_df <- reduce(dfs, bind_rows)
Обработка данных Выбор столбцов по названию (всегда, даже если много столбцов с похожими названиями) tidyselect helpers select(url, longitude, latitude, matches(“^id_park_”), matches(“^path_park_”), matches(“^NDVI_mean”), everything())
Обработка данных Использовал case_when всегда
map_chr для больших замен
Меньше хардкода, лаконичнее.
Работа с json Проблемы с переменными-списками unnest_wider

Быстро и безопасно

flats %>% unnest_wider(building_info) %>% unnest_wider(property_details) %>% unnest_wider(location)

Функции Много файлов с функциями
devtools
Автодокументация, реиспользуемость. Только учусь.
Функции Повторяющиеся source
devtools::load_all()
Удобно, красиво.
Дебаггинг Проверка на NA
skimr::skim(df)
Если забываю, то делаю так, но это хуже:
df %>% is.na %>% colSums()
Быстро и наглядно.
Итераторы 1:length(x) | seq_along(x) | Безопаснее при пустых объектов | seq_along(x) Безопаснее при пустых объектов. Ещё это лучше смотрится, но красивее, чем x[1:end], как в Julia, ещё никто не придумал.
Операции с данными Использовал filter + повторяющиеся условия. Использую filter + across или any_of Меньше дублирований.
Операции с данными Много mutate подряд Сочетание mutate + across + case_when Компактно, удобно поддерживать.

Этот список я буду дополнять. Когда-нибудь сделаю отчётный пост об успехах.